import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;



public class FSMachine 
{
	public enum enumState 
	{
		MOVETO,
		TALKTO,
		GUESS,
		GATHEREVIDENCE,
		KILLAGENT,
		WANDER,
	}
	
	public enum enumEvent
	{
		KILLING;
	}
	
	private HashMap<enumState, State> 	m_stateList = new HashMap<enumState, State>();
	private MoveTo						m_moveTo;
	private TalkTo						m_talkTo;
	private GatherEvidence				m_gatherEvidence;
	private Guess						m_guess;
	private KillAgent					m_killAgent;
	private Wander						m_wander;
	private State						m_curState;
	private Queue<enumEvent>			m_eventQueue;
    private int myID;
	
	public void Create(Integer agentId)
	{
		m_moveTo 			= new MoveTo(this);
		m_talkTo 			= new TalkTo(this);
		m_gatherEvidence 	= new GatherEvidence(this);
		m_guess				= new Guess(this);
		m_killAgent			= new KillAgent(this);
		m_wander			= new Wander(this);
		m_eventQueue		= new LinkedList<enumEvent>();
		
		m_stateList.put(enumState.MOVETO, m_moveTo);
		m_stateList.put(enumState.TALKTO, m_talkTo);
		m_stateList.put(enumState.GUESS, m_guess);
		m_stateList.put(enumState.GATHEREVIDENCE, m_gatherEvidence);
		m_stateList.put(enumState.KILLAGENT, m_killAgent);
		m_stateList.put(enumState.WANDER, m_wander);
		myID = agentId;
		
		m_curState = m_guess;
		m_curState.Enter(myID,-1);
		
	}
	
	public void Update() {
		enumEvent event;

		// if there is an event, handle the event first
		if (!m_eventQueue.isEmpty()) {
			event = m_eventQueue.poll();

			switch (event) {
			case KILLING:
				ChangeState(enumState.GUESS, myID, -1);
				break;
			}
		} else
			try {
				m_curState.Execute();
			} catch (Exception e) {
				System.out.println(e.getStackTrace());
			}
	}
	
	public void ChangeState(enumState newState, int myID,int otherID)
	{
		m_curState.Exit();
		
		boolean noExecute = (newState.equals(enumState.GUESS) && (m_curState instanceof TalkTo));
		m_curState = m_stateList.get(newState);
		m_curState.Enter(myID,otherID);
		
		// This prevents an infinite loop if everyone is right next to each other trying to talk.
		if (!noExecute) {
			m_curState.Execute();
		}
	}
	
	public void AddEvent(enumEvent event)
	{
		m_eventQueue.add(event);
	}
}
